#ifndef mbObj
#include "sys_ext.h" 
#include "os_obj.h"
#include "mbapp.h"
#include "com_def.h"

mb_obj_type mbObj;
#define mbPORT  USART2
#define mbURT_IRQn                   USART2_IRQn
#endif

__STATIC_INLINE void mbswTimerEnable(void);
__STATIC_INLINE void mbswTimerDisable(void);
__STATIC_INLINE void mb_timer_handler(void);
static void mb_cb_set(void);
static void mbObjInit(mb_mode_type mbMode);
static void mbPortTx1Rx0Enable(uint8_t mode);
static void mb_port_Init(mb_mode_type mbMode, uint32_t ulBaudRate, mb_parity_type eParity);
static void mbDataSend(void);
static void mb_port_hal_cfg(void);
static void (*mb_byte_send)(uint8_t dat);

/*****************************************************************************//*!
* @brief mb_byte_send
* @param   dat
* @return  none
* @ Pass/ Fail criteria: none
*****************************************************************************/

static void mb_rtu_byte_send(uint8_t dat)
{
	mbPORT->DT = dat;
}

static void mb_asc_byte_send(uint8_t dat)
{
	mbPORT->DT = dat | 0x80;
}

/*****************************************************************************//*!
* @brief UART0 RX interrupt routine.
* @brief   Uart interrupt.
*             
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
void mbISR() 
{
    volatile uint32_t IntSt;
	volatile uint8_t Data; 
     
	mbObj.timeout_cnt = 0;
    
    IntSt = mbPORT->STS;
	
    if(IntSt & USART_STS_RDNE)
    {
        Data = mbPORT->DT;
        
        if((IntSt & (USART_STS_PERR | USART_STS_FERR | USART_STS_ORERR) ) != 0)   //帧错误 //只读，由硬件管理
        {
            if(mbObj.rcv_cnt >= 1)
            {
                mbObj.err_st.bits.hal = 1;
            }
        }
        
		mb_data_rcv(&mbObj, Data);
    }
	else if( (mbObj.snd_size <= mbObj.snd_cnt) && (IntSt & USART_STS_TRAC))
    {
		mb_send_end(&mbObj);
		mbPortTx1Rx0Enable(0);    
    }
    else if( IntSt & USART_STS_TDE)
    {
		if(mb_data_send(&mbObj, mb_byte_send, 1))
		{
            mbPORT->CTRL1 &= ~((uint32_t)(USART_CTRL1_TDEIEN));
            mbPORT->CTRL1 |= (uint32_t)(USART_CTRL1_TRACIEN);
		} 
    }
    else
    {
        
    }
}

/*****************************************************************************//*!
* @brief   	com modle init .
*               
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
static void mb_port_Init(mb_mode_type mbMode, uint32_t ulBaudRate, mb_parity_type eParity) 
{
    USART_InitType cfg;

    mb_port_hal_cfg();
    
    mbObjInit(mbMode);

    cfg.USART_BaudRate = ulBaudRate;
    cfg.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    cfg.USART_HardwareFlowControl = 0;
    
	mb_byte_send = mb_rtu_byte_send;
	if(mbMode == MB_RTU_MASTER || mbMode == MB_RTU_SLAVE)
	{
		// rtu mode
		if (MB_PAR_NONE == eParity) 
		{
			cfg.USART_Parity = USART_Parity_No;
			cfg.USART_StopBits = USART_StopBits_2;
			cfg.USART_WordLength = USART_WordLength_8b;
		} 
		else if (MB_PAR_NONE_1S == eParity) 
		{
			cfg.USART_Parity = USART_Parity_No;
			cfg.USART_StopBits = USART_StopBits_1;
			cfg.USART_WordLength = USART_WordLength_8b;
		} 
		else if (MB_PAR_ODD == eParity)
		{
			cfg.USART_Parity = USART_Parity_Odd;
			cfg.USART_StopBits = USART_StopBits_1;
			cfg.USART_WordLength = USART_WordLength_9b;
		} 
		else
		{
			cfg.USART_Parity = USART_Parity_Even;
			cfg.USART_StopBits = USART_StopBits_1;
			cfg.USART_WordLength = USART_WordLength_9b;
		}
		
		mbObj.run_st.bits.rtu_mode = 1;
	}
	else
	{
		// asc mode
		if (MB_PAR_NONE == eParity) 
		{
			cfg.USART_Parity = USART_Parity_No;
			cfg.USART_StopBits = USART_StopBits_1;
			cfg.USART_WordLength = USART_WordLength_8b;
			mb_byte_send = mb_asc_byte_send;
		} 
		else if (MB_PAR_ODD == eParity)
		{
			cfg.USART_Parity = USART_Parity_Odd;
			cfg.USART_StopBits = USART_StopBits_1;
			cfg.USART_WordLength = USART_WordLength_8b;
		} 
		else 
		{
			cfg.USART_Parity = USART_Parity_Even;
			cfg.USART_StopBits = USART_StopBits_1;
			cfg.USART_WordLength = USART_WordLength_8b;
		}
		
		mbObj.run_st.bits.rtu_mode = 0;
	}
	
	// rtu timer
	if(mbObj.run_st.bits.rtu_mode == 0)
	{
		mbObj.rtu_timer_sv = 240;
		mbObj.timeout_set = 500;
	}
	else
	{
		if (ulBaudRate > 19200) 
		{
			mbObj.rtu_timer_sv = 3;
		} else 
		{
			mbObj.rtu_timer_sv = (com_timer_cal(ulBaudRate, (35*11+9)/10, 300, 12000) + 99)/100;
		}		
	}
    
    USART_Init(mbPORT, &cfg);

    USART_Cmd(mbPORT, ENABLE);
    
    nvic_irq_set(mbURT_IRQn,0x0F,1);

    mbPortTx1Rx0Enable(0);
}

/*****************************************************************************//*!
*
* @brief   Uart En or Dis.
*             
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/

static void mbPortTx1Rx0Enable(uint8_t mode) {
	volatile uint8_t u8Temp;
	
	if(0 == mode)
	{
        mbRxEnable();
        
		mbPORT->CTRL1   &= ~((uint32_t)USART_CTRL1_TDEIEN | USART_CTRL1_TRACIEN);	
		mbPORT->CTRL1   |= (uint32_t)USART_CTRL1_REN;
		
		u8Temp        = mbPORT->DT;	
		while((mbPORT->STS & (USART_STS_RDNE | USART_STS_ORERR)) != 0)
		{
            u8Temp        = mbPORT->DT;
            __DSB();
		}
		
		mbPORT->CTRL1   |= USART_CTRL1_RDNEIEN;
	}
	else
	{
		mbPORT->CTRL1   &= ~((uint32_t)USART_CTRL1_RDNEIEN | USART_CTRL1_REN);	
		
		mbPORT->CTRL1   |= (uint32_t)USART_CTRL1_TEN;		
		mbTxEnable();
    	
		// mbPORT->DT     =  mbObj.adu_buff[mbObj.snd_cnt++];
		// mb_data_send(&mbObj, mb_byte_send, 1)
		mbPORT->CTRL1   |= (uint32_t)(USART_CTRL1_TDEIEN);
	}
}

/*****************************************************************************//*!
*
* @brief   Send data.
*             
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
static void mbDataSend(void) 
{
	mbObj.adu_buff[mbObj.snd_size++] = 11;
	mbObj.adu_buff[mbObj.snd_size++] = 13;
    mbPortTx1Rx0Enable(1);
}


/*****************************************************************************//*!
*
* @brief   RTU timer enable.
*             
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
__STATIC_INLINE void mbswTimerEnable(void)
{
    mbObj.rtu_timer_cnt = 0;	
    mbObj.b_rtu_timer_on = 1;
}


/*****************************************************************************//*!
*
* @brief   Timeout handle.
*          called from ext timer 1 ms
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
__STATIC_INLINE void mb_timer_handler(void)
{
   mb_rtu_timer_run(&mbObj);
}

/*****************************************************************************//*!
*
* @brief   mb object init.
*             
* @param   none
*
* @return  TURE
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
static void mbObjInit(mb_mode_type mbMode) {

    mb_obj_init(&mbObj);
    mbObj.adu_send = &mbDataSend;

    mb_cb_set();
    
    mbObj.master.err_cnt = 0;    
    
    //SLAVE FUNCTION INIT
    if (MB_RTU_MASTER == mbMode || mbMode == ASCII_MASTER)
	{
		mbObj.run_st.bits.master_mode = 1;
    }
	else
	{
		mbObj.run_st.bits.master_mode = 0;
	}
}
